﻿namespace ZyGame.Transport
{
    using System;
    using System.Collections.Generic;
    using UnityEngine.Networking;
    using System.Collections;
    using System.Text;
    using ZyGame.Execute;

    public enum WebMethod
    {
        GET,
        POST,
        PUT,
        DELETE,
    }

    class Header
    {
        public string key;
        public string value;
    }

    public class WebRequest
    {
        private string url;
        private byte[] data;
        private WebMethod method;
        private Runnable<string> runnable;
        private Dictionary<string, string> headers;

        internal WebRequest(string url, WebMethod method)
        {
            this.url = url;
            this.method = method;
            this.data = Array.Empty<byte>();
            this.headers = new Dictionary<string, string>();
        }

        public Runnable<string> OnStart()
        {
            Client.Running.TryGetOrCreate(url, out runnable);
            runnable.Execute(Runnable);
            return runnable;
        }

        IEnumerator Runnable()
        {
            using UnityWebRequest request = method switch
            {
                WebMethod.POST => UnityWebRequest.Post(url, Encoding.UTF8.GetString(data)),
                WebMethod.GET => UnityWebRequest.Get(url),
                WebMethod.PUT => UnityWebRequest.Put(url, Encoding.UTF8.GetString(data)),
                WebMethod.DELETE => UnityWebRequest.Delete(url),
                _ => null,
            };

            if (request is null)
            {
                runnable.SetResult(new Exception("unsuport method:" + method));
                yield break;
            }

            request.certificateHandler = new WebReqSkipCert();
            if (headers.Count is not 0)
            {
                foreach (var item in headers)
                {
                    try
                    {
                        request.SetRequestHeader(item.Key, item.Value);
                    }
                    catch (Exception e)
                    {
                        Client.Console.WriteLine(item.Key, item.Value, e);
                    }
                }
            }

            if (this.method == WebMethod.POST || this.method == WebMethod.PUT)
            {
                request.uploadHandler = new UploadHandlerRaw(data);
            }

            Client.Console.WriteLine(method, request.url, Encoding.UTF8.GetString(data));
            yield return request.SendWebRequest();
            if (!request.isDone || request.result != UnityWebRequest.Result.Success)
            {
                runnable.SetResult(new Exception($"{request.error}\n{request.downloadHandler.text}"));
                Client.Console.WriteError($"{request.error}\n{request.downloadHandler.text}");
                yield break;
            }

            if (runnable == null)
            {
                yield break;
            }

            Client.Console.WriteLine(request.downloadHandler.text);
            runnable.SetResult(request.downloadHandler.text);
        }

        public WebRequest SetHeadder(string name, string value)
        {
            if (headers.ContainsKey(name))
            {
                throw new Exception("the header is already exist. key:" + name);
            }

            headers.Add(name, value);
            return this;
        }

        public WebRequest SetHeadder(Dictionary<string, string> headers)
        {
            foreach (var header in headers)
            {
                SetHeadder(header.Key, header.Value);
            }

            return this;
        }

        public WebRequest UploadData(object data) => UploadData(data.ToJson().GetBytes());

        public WebRequest UploadData(byte[] bytes)
        {
            if (!headers.TryGetValue("Content-Type", out string value))
            {
                headers.Add("Content-Type", "application/json");
                this.data = bytes;
            }

            this.data = bytes;
            return this;
        }
    }
}